
use llua::*;
use hackit::Registers;
use hackit::AsByteArray;
use core::slice::{from_raw_parts, from_raw_parts_mut};
use core::mem::transmute;

#[cfg(target_arch = "x86")]
use std::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;

#[cfg(windows)]
use winapi::um::winnt::{CONTEXT, WOW64_CONTEXT};

// regid from capstone-rs
pub mod regid {
    pub const X86_REG_INVALID: u32 = 0;
    pub const X86_REG_AH: u32 = 1;
    pub const X86_REG_AL: u32 = 2;
    pub const X86_REG_AX: u32 = 3;
    pub const X86_REG_BH: u32 = 4;
    pub const X86_REG_BL: u32 = 5;
    pub const X86_REG_BP: u32 = 6;
    pub const X86_REG_BPL: u32 = 7;
    pub const X86_REG_BX: u32 = 8;
    pub const X86_REG_CH: u32 = 9;
    pub const X86_REG_CL: u32 = 10;
    pub const X86_REG_CS: u32 = 11;
    pub const X86_REG_CX: u32 = 12;
    pub const X86_REG_DH: u32 = 13;
    pub const X86_REG_DI: u32 = 14;
    pub const X86_REG_DIL: u32 = 15;
    pub const X86_REG_DL: u32 = 16;
    pub const X86_REG_DS: u32 = 17;
    pub const X86_REG_DX: u32 = 18;
    pub const X86_REG_EAX: u32 = 19;
    pub const X86_REG_EBP: u32 = 20;
    pub const X86_REG_EBX: u32 = 21;
    pub const X86_REG_ECX: u32 = 22;
    pub const X86_REG_EDI: u32 = 23;
    pub const X86_REG_EDX: u32 = 24;
    pub const X86_REG_EFLAGS: u32 = 25;
    pub const X86_REG_EIP: u32 = 26;
    pub const X86_REG_EIZ: u32 = 27;
    pub const X86_REG_ES: u32 = 28;
    pub const X86_REG_ESI: u32 = 29;
    pub const X86_REG_ESP: u32 = 30;
    pub const X86_REG_FPSW: u32 = 31;
    pub const X86_REG_FS: u32 = 32;
    pub const X86_REG_GS: u32 = 33;
    pub const X86_REG_IP: u32 = 34;
    pub const X86_REG_RAX: u32 = 35;
    pub const X86_REG_RBP: u32 = 36;
    pub const X86_REG_RBX: u32 = 37;
    pub const X86_REG_RCX: u32 = 38;
    pub const X86_REG_RDI: u32 = 39;
    pub const X86_REG_RDX: u32 = 40;
    pub const X86_REG_RIP: u32 = 41;
    pub const X86_REG_RIZ: u32 = 42;
    pub const X86_REG_RSI: u32 = 43;
    pub const X86_REG_RSP: u32 = 44;
    pub const X86_REG_SI: u32 = 45;
    pub const X86_REG_SIL: u32 = 46;
    pub const X86_REG_SP: u32 = 47;
    pub const X86_REG_SPL: u32 = 48;
    pub const X86_REG_SS: u32 = 49;
    pub const X86_REG_CR0: u32 = 50;
    pub const X86_REG_CR1: u32 = 51;
    pub const X86_REG_CR2: u32 = 52;
    pub const X86_REG_CR3: u32 = 53;
    pub const X86_REG_CR4: u32 = 54;
    pub const X86_REG_CR5: u32 = 55;
    pub const X86_REG_CR6: u32 = 56;
    pub const X86_REG_CR7: u32 = 57;
    pub const X86_REG_CR8: u32 = 58;
    pub const X86_REG_CR9: u32 = 59;
    pub const X86_REG_CR10: u32 = 60;
    pub const X86_REG_CR11: u32 = 61;
    pub const X86_REG_CR12: u32 = 62;
    pub const X86_REG_CR13: u32 = 63;
    pub const X86_REG_CR14: u32 = 64;
    pub const X86_REG_CR15: u32 = 65;
    pub const X86_REG_DR0: u32 = 66;
    pub const X86_REG_DR1: u32 = 67;
    pub const X86_REG_DR2: u32 = 68;
    pub const X86_REG_DR3: u32 = 69;
    pub const X86_REG_DR4: u32 = 70;
    pub const X86_REG_DR5: u32 = 71;
    pub const X86_REG_DR6: u32 = 72;
    pub const X86_REG_DR7: u32 = 73;
    pub const X86_REG_DR8: u32 = 74;
    pub const X86_REG_DR9: u32 = 75;
    pub const X86_REG_DR10: u32 = 76;
    pub const X86_REG_DR11: u32 = 77;
    pub const X86_REG_DR12: u32 = 78;
    pub const X86_REG_DR13: u32 = 79;
    pub const X86_REG_DR14: u32 = 80;
    pub const X86_REG_DR15: u32 = 81;
    pub const X86_REG_FP0: u32 = 82;
    pub const X86_REG_FP1: u32 = 83;
    pub const X86_REG_FP2: u32 = 84;
    pub const X86_REG_FP3: u32 = 85;
    pub const X86_REG_FP4: u32 = 86;
    pub const X86_REG_FP5: u32 = 87;
    pub const X86_REG_FP6: u32 = 88;
    pub const X86_REG_FP7: u32 = 89;
    pub const X86_REG_K0: u32 = 90;
    pub const X86_REG_K1: u32 = 91;
    pub const X86_REG_K2: u32 = 92;
    pub const X86_REG_K3: u32 = 93;
    pub const X86_REG_K4: u32 = 94;
    pub const X86_REG_K5: u32 = 95;
    pub const X86_REG_K6: u32 = 96;
    pub const X86_REG_K7: u32 = 97;
    pub const X86_REG_MM0: u32 = 98;
    pub const X86_REG_MM1: u32 = 99;
    pub const X86_REG_MM2: u32 = 100;
    pub const X86_REG_MM3: u32 = 101;
    pub const X86_REG_MM4: u32 = 102;
    pub const X86_REG_MM5: u32 = 103;
    pub const X86_REG_MM6: u32 = 104;
    pub const X86_REG_MM7: u32 = 105;
    pub const X86_REG_R8: u32 = 106;
    pub const X86_REG_R9: u32 = 107;
    pub const X86_REG_R10: u32 = 108;
    pub const X86_REG_R11: u32 = 109;
    pub const X86_REG_R12: u32 = 110;
    pub const X86_REG_R13: u32 = 111;
    pub const X86_REG_R14: u32 = 112;
    pub const X86_REG_R15: u32 = 113;
    pub const X86_REG_ST0: u32 = 114;
    pub const X86_REG_ST1: u32 = 115;
    pub const X86_REG_ST2: u32 = 116;
    pub const X86_REG_ST3: u32 = 117;
    pub const X86_REG_ST4: u32 = 118;
    pub const X86_REG_ST5: u32 = 119;
    pub const X86_REG_ST6: u32 = 120;
    pub const X86_REG_ST7: u32 = 121;
    pub const X86_REG_XMM0: u32 = 122;
    pub const X86_REG_XMM1: u32 = 123;
    pub const X86_REG_XMM2: u32 = 124;
    pub const X86_REG_XMM3: u32 = 125;
    pub const X86_REG_XMM4: u32 = 126;
    pub const X86_REG_XMM5: u32 = 127;
    pub const X86_REG_XMM6: u32 = 128;
    pub const X86_REG_XMM7: u32 = 129;
    pub const X86_REG_XMM8: u32 = 130;
    pub const X86_REG_XMM9: u32 = 131;
    pub const X86_REG_XMM10: u32 = 132;
    pub const X86_REG_XMM11: u32 = 133;
    pub const X86_REG_XMM12: u32 = 134;
    pub const X86_REG_XMM13: u32 = 135;
    pub const X86_REG_XMM14: u32 = 136;
    pub const X86_REG_XMM15: u32 = 137;
    pub const X86_REG_XMM16: u32 = 138;
    pub const X86_REG_XMM17: u32 = 139;
    pub const X86_REG_XMM18: u32 = 140;
    pub const X86_REG_XMM19: u32 = 141;
    pub const X86_REG_XMM20: u32 = 142;
    pub const X86_REG_XMM21: u32 = 143;
    pub const X86_REG_XMM22: u32 = 144;
    pub const X86_REG_XMM23: u32 = 145;
    pub const X86_REG_XMM24: u32 = 146;
    pub const X86_REG_XMM25: u32 = 147;
    pub const X86_REG_XMM26: u32 = 148;
    pub const X86_REG_XMM27: u32 = 149;
    pub const X86_REG_XMM28: u32 = 150;
    pub const X86_REG_XMM29: u32 = 151;
    pub const X86_REG_XMM30: u32 = 152;
    pub const X86_REG_XMM31: u32 = 153;
    pub const X86_REG_YMM0: u32 = 154;
    pub const X86_REG_YMM1: u32 = 155;
    pub const X86_REG_YMM2: u32 = 156;
    pub const X86_REG_YMM3: u32 = 157;
    pub const X86_REG_YMM4: u32 = 158;
    pub const X86_REG_YMM5: u32 = 159;
    pub const X86_REG_YMM6: u32 = 160;
    pub const X86_REG_YMM7: u32 = 161;
    pub const X86_REG_YMM8: u32 = 162;
    pub const X86_REG_YMM9: u32 = 163;
    pub const X86_REG_YMM10: u32 = 164;
    pub const X86_REG_YMM11: u32 = 165;
    pub const X86_REG_YMM12: u32 = 166;
    pub const X86_REG_YMM13: u32 = 167;
    pub const X86_REG_YMM14: u32 = 168;
    pub const X86_REG_YMM15: u32 = 169;
    pub const X86_REG_YMM16: u32 = 170;
    pub const X86_REG_YMM17: u32 = 171;
    pub const X86_REG_YMM18: u32 = 172;
    pub const X86_REG_YMM19: u32 = 173;
    pub const X86_REG_YMM20: u32 = 174;
    pub const X86_REG_YMM21: u32 = 175;
    pub const X86_REG_YMM22: u32 = 176;
    pub const X86_REG_YMM23: u32 = 177;
    pub const X86_REG_YMM24: u32 = 178;
    pub const X86_REG_YMM25: u32 = 179;
    pub const X86_REG_YMM26: u32 = 180;
    pub const X86_REG_YMM27: u32 = 181;
    pub const X86_REG_YMM28: u32 = 182;
    pub const X86_REG_YMM29: u32 = 183;
    pub const X86_REG_YMM30: u32 = 184;
    pub const X86_REG_YMM31: u32 = 185;
    pub const X86_REG_ZMM0: u32 = 186;
    pub const X86_REG_ZMM1: u32 = 187;
    pub const X86_REG_ZMM2: u32 = 188;
    pub const X86_REG_ZMM3: u32 = 189;
    pub const X86_REG_ZMM4: u32 = 190;
    pub const X86_REG_ZMM5: u32 = 191;
    pub const X86_REG_ZMM6: u32 = 192;
    pub const X86_REG_ZMM7: u32 = 193;
    pub const X86_REG_ZMM8: u32 = 194;
    pub const X86_REG_ZMM9: u32 = 195;
    pub const X86_REG_ZMM10: u32 = 196;
    pub const X86_REG_ZMM11: u32 = 197;
    pub const X86_REG_ZMM12: u32 = 198;
    pub const X86_REG_ZMM13: u32 = 199;
    pub const X86_REG_ZMM14: u32 = 200;
    pub const X86_REG_ZMM15: u32 = 201;
    pub const X86_REG_ZMM16: u32 = 202;
    pub const X86_REG_ZMM17: u32 = 203;
    pub const X86_REG_ZMM18: u32 = 204;
    pub const X86_REG_ZMM19: u32 = 205;
    pub const X86_REG_ZMM20: u32 = 206;
    pub const X86_REG_ZMM21: u32 = 207;
    pub const X86_REG_ZMM22: u32 = 208;
    pub const X86_REG_ZMM23: u32 = 209;
    pub const X86_REG_ZMM24: u32 = 210;
    pub const X86_REG_ZMM25: u32 = 211;
    pub const X86_REG_ZMM26: u32 = 212;
    pub const X86_REG_ZMM27: u32 = 213;
    pub const X86_REG_ZMM28: u32 = 214;
    pub const X86_REG_ZMM29: u32 = 215;
    pub const X86_REG_ZMM30: u32 = 216;
    pub const X86_REG_ZMM31: u32 = 217;
    pub const X86_REG_R8B: u32 = 218;
    pub const X86_REG_R9B: u32 = 219;
    pub const X86_REG_R10B: u32 = 220;
    pub const X86_REG_R11B: u32 = 221;
    pub const X86_REG_R12B: u32 = 222;
    pub const X86_REG_R13B: u32 = 223;
    pub const X86_REG_R14B: u32 = 224;
    pub const X86_REG_R15B: u32 = 225;
    pub const X86_REG_R8D: u32 = 226;
    pub const X86_REG_R9D: u32 = 227;
    pub const X86_REG_R10D: u32 = 228;
    pub const X86_REG_R11D: u32 = 229;
    pub const X86_REG_R12D: u32 = 230;
    pub const X86_REG_R13D: u32 = 231;
    pub const X86_REG_R14D: u32 = 232;
    pub const X86_REG_R15D: u32 = 233;
    pub const X86_REG_R8W: u32 = 234;
    pub const X86_REG_R9W: u32 = 235;
    pub const X86_REG_R10W: u32 = 236;
    pub const X86_REG_R11W: u32 = 237;
    pub const X86_REG_R12W: u32 = 238;
    pub const X86_REG_R13W: u32 = 239;
    pub const X86_REG_R14W: u32 = 240;
    pub const X86_REG_R15W: u32 = 241;
    pub const X86_REG_BND0: u32 = 242;
    pub const X86_REG_BND1: u32 = 243;
    pub const X86_REG_BND2: u32 = 244;
    pub const X86_REG_BND3: u32 = 245;
    pub const X86_REG_ENDING: u32 = 246;
}

pub const COMM_REG_SP: u32 = 0x10001;
pub const COMM_REG_PC: u32 = 0x10002;

use regid::*;

#[derive(Copy, Clone)]
pub enum CpuReg {
    Int(usize),
    Flt(f64),
}

impl CpuReg {
    #[inline]
    pub fn as_int(&self) -> usize {
        match *self { Self::Int(n) => n, Self::Flt(n) => n as usize }
    }

    #[inline]
    pub fn as_flt(&self) -> f64 {
        match *self { Self::Int(n) => n as f64, Self::Flt(n) => n }
    }
}

impl Into<u64> for CpuReg {
    #[inline]
    fn into(self) -> u64 { self.as_int() as u64 }
}

impl Into<u32> for CpuReg {
    #[inline]
    fn into(self) -> u32 { self.as_int() as u32 }
}

impl Into<usize> for CpuReg {
    #[inline]
    fn into(self) -> usize { self.as_int() }
}

impl ToLua for CpuReg {
    fn to_lua(self, s: State) {
        match self {
            CpuReg::Int(n) => s.push_integer(n as lua_Integer),
            CpuReg::Flt(n) => s.push_number(n as lua_Number),
        };
    }
}

pub trait FromUsize {
    fn from_usize(v: usize) -> Self;
    fn to_usize(&self) -> usize;
}

impl FromUsize for u32 {
    fn from_usize(v: usize) -> Self { v as Self }
    fn to_usize(&self) -> usize { *self as usize }
}

impl FromUsize for u64 {
    fn from_usize(v: usize) -> Self { v as Self }
    fn to_usize(&self) -> usize { *self as usize }
}

pub trait CommRegs {
    type REG: FromUsize + Copy;

    fn ip(&mut self) -> &mut Self::REG;
    fn sp(&mut self) -> &mut Self::REG;
}

// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-context
#[cfg(target_arch = "x86_64")]
impl CommRegs for CONTEXT {
    type REG = u64;

    #[inline]
    fn ip(&mut self) -> &mut Self::REG { &mut self.Rip }
    #[inline]
    fn sp(&mut self) -> &mut Self::REG { &mut self.Rsp }
}

#[cfg(target_arch = "x86")]
impl CommRegs for CONTEXT {
    type REG = u32;

    fn ip(&mut self) -> &mut Self::REG { &mut self.Eip }
    fn sp(&mut self) -> &mut Self::REG { &mut self.Esp }
}

impl CommRegs for WOW64_CONTEXT {
    type REG = u32;

    #[inline]
    fn ip(&mut self) -> &mut Self::REG { &mut self.Eip }
    #[inline]
    fn sp(&mut self) -> &mut Self::REG { &mut self.Esp }
}

#[inline]
unsafe fn mutable<T: Sized>(t: &T) -> &mut T {
    transmute(transmute::<_, usize>(t))
}

#[cfg(target_arch = "x86_64")]
impl UDbgRegs for CONTEXT {
    fn get_reg(&self, id: u32) -> Option<CpuReg> {
        let c = self;
        Some(CpuReg::Int(match id {
            X86_REG_RAX => c.Rax,
            X86_REG_RBX => c.Rbx,
            X86_REG_RCX => c.Rcx,
            X86_REG_RDX => c.Rdx,
            X86_REG_RBP => c.Rbp,
            X86_REG_RSI => c.Rsi,
            X86_REG_RDI => c.Rdi,
            X86_REG_R8 ..= X86_REG_R15 => unsafe {
                let i = (id - X86_REG_R8) as usize;
                from_raw_parts(&c.R8, 8)[i]
            }
            X86_REG_DR0 => c.Dr0,
            X86_REG_DR1 => c.Dr1,
            X86_REG_DR2 => c.Dr2,
            X86_REG_DR3 => c.Dr3,
            X86_REG_DR6 => c.Dr6,
            X86_REG_DR7 => c.Dr7,
            X86_REG_RSP | COMM_REG_SP => c.Rsp,
            X86_REG_RIP | COMM_REG_PC => c.Rip,
            X86_REG_EFLAGS => c.EFlags as u64,
            X86_REG_MM0 ..= X86_REG_MM7 => unsafe {
                let i = (id - X86_REG_MM0) as usize;
                let mut f = [0.0; 4];
                _mm_storeu_ps(f.as_mut_ptr(), transmute(from_raw_parts(&mutable(c).u.s_mut().Xmm0, 100)[i]));
                return CpuReg::Flt(f[0] as f64).into();
            }
            X86_REG_XMM0 ..= X86_REG_XMM15 => unsafe {
                let i = (id - X86_REG_XMM0) as usize;
                let mut f = [0.0; 2];
                _mm_storeu_pd(f.as_mut_ptr(), transmute(from_raw_parts(&mutable(c).u.s_mut().Xmm0, 100)[i]));
                return CpuReg::Flt(f[0]).into();
            }
            _ => return None,
        } as usize))
    }

    fn set_reg(&mut self, id: u32, val: CpuReg) {
        let c = self;
        match id {
            X86_REG_RAX => c.Rax = val.into(),
            X86_REG_RBX => c.Rbx = val.into(),
            X86_REG_RCX => c.Rcx = val.into(),
            X86_REG_RDX => c.Rdx = val.into(),
            X86_REG_RBP => c.Rbp = val.into(),
            X86_REG_RSI => c.Rsi = val.into(),
            X86_REG_RDI => c.Rdi = val.into(),
            X86_REG_R8 => c.R8 = val.into(),
            X86_REG_R9 => c.R9 = val.into(),
            X86_REG_R10 => c.R10 = val.into(),
            X86_REG_R11 => c.R11 = val.into(),
            X86_REG_R12 => c.R12 = val.into(),
            X86_REG_R13 => c.R13 = val.into(),
            X86_REG_R14 => c.R14 = val.into(),
            X86_REG_R15 => c.R15 = val.into(),
            X86_REG_RSP | COMM_REG_SP => c.Rsp = val.into(),
            X86_REG_RIP | COMM_REG_PC => c.Rip = val.into(),
            X86_REG_EFLAGS => c.EFlags = val.into(),
            X86_REG_MM0 ..= X86_REG_MM7 => unsafe {
                let i = (id - X86_REG_MM0) as usize;
                from_raw_parts_mut(&mut c.u.s_mut().Xmm0, 100)[i] = transmute(_mm_set1_ps(val.as_flt() as f32));
            }
            X86_REG_XMM0 ..= X86_REG_XMM15 => unsafe {
                let i = (id - X86_REG_XMM0) as usize;
                from_raw_parts_mut(&mut c.u.s_mut().Xmm0, 100)[i] = transmute(_mm_set1_pd(val.as_flt()));
            }
            _ => {}
        };
    }

    fn to_regs(&self) -> RegType {
        RegType::X64(context_to_regs(self))
    }

    fn as_raw(&self) -> Option<&CONTEXT> { Some(self) }
}

#[cfg(target_arch = "x86_64")]
impl UDbgRegs for WOW64_CONTEXT {
    fn get_reg(&self, id: u32) -> Option<CpuReg> {
        let c = self;
        Some(CpuReg::Int(match id {
            X86_REG_EAX => c.Eax,
            X86_REG_EBX => c.Ebx,
            X86_REG_ECX => c.Ecx,
            X86_REG_EDX => c.Edx,
            X86_REG_EBP => c.Ebp,
            X86_REG_ESI => c.Esi,
            X86_REG_EDI => c.Edi,
            X86_REG_DR0 => c.Dr0,
            X86_REG_DR1 => c.Dr1,
            X86_REG_DR2 => c.Dr2,
            X86_REG_DR3 => c.Dr3,
            X86_REG_DR6 => c.Dr6,
            X86_REG_DR7 => c.Dr7,
            X86_REG_ESP | COMM_REG_SP => c.Esp,
            X86_REG_EIP | COMM_REG_PC => c.Eip,
            X86_REG_EFLAGS => c.EFlags,
            _ => return None,
        } as usize))
    }

    fn set_reg(&mut self, id: u32, val: CpuReg) {
        let c = self;
        match id {
            X86_REG_EAX => c.Eax = val.into(),
            X86_REG_EBX => c.Ebx = val.into(),
            X86_REG_ECX => c.Ecx = val.into(),
            X86_REG_EDX => c.Edx = val.into(),
            X86_REG_EBP => c.Ebp = val.into(),
            X86_REG_ESI => c.Esi = val.into(),
            X86_REG_EDI => c.Edi = val.into(),
            X86_REG_ESP | COMM_REG_SP => c.Esp = val.into(),
            X86_REG_EIP | COMM_REG_PC => c.Eip = val.into(),
            X86_REG_EFLAGS => c.EFlags = val.into(),
            _ => {}
        };
    }

    fn to_regs(&self) -> RegType {
        RegType::X86(context_to_regs32(self))
    }

    fn as_wow64(&self) -> Option<&WOW64_CONTEXT> { Some(self) }
}

#[cfg(target_arch = "x86_64")]
pub fn context_to_regs(c: &CONTEXT) -> Registers {
    Registers {
        rax: c.Rax,
        rbx: c.Rbx,
        rcx: c.Rcx,
        rdx: c.Rdx,
        rbp: c.Rbp,
        rsp: c.Rsp,
        rsi: c.Rsi,
        rdi: c.Rdi,
        r8: c.R8,
        r9: c.R9,
        r10: c.R10,
        r11: c.R11,
        r12: c.R12,
        r13: c.R13,
        r14: c.R14,
        r15: c.R15,
        rip: c.Rip,
        rflags: c.EFlags as u64,
        cs: c.SegCs,
        ds: c.SegDs,
        es: c.SegEs,
        fs: c.SegFs,
        gs: c.SegGs,
        ss: c.SegSs,
    }
}

#[cfg(target_arch = "x86_64")]
pub fn context_to_regs32(c: &WOW64_CONTEXT) -> Registers32 {
    Registers32 {
        eax: c.Eax,
        ebx: c.Ebx,
        ecx: c.Ecx,
        edx: c.Edx,
        ebp: c.Ebp,
        esp: c.Esp,
        esi: c.Esi,
        edi: c.Edi,
        eip: c.Eip,
        eflags: c.EFlags as u32,
        cs: c.SegCs as u16,
        ds: c.SegDs as u16,
        es: c.SegEs as u16,
        fs: c.SegFs as u16,
        gs: c.SegGs as u16,
        ss: c.SegSs as u16,
    }
}

#[cfg(target_arch = "x86")]
pub fn context_to_regs(c: &CONTEXT) -> Registers {
    Registers {
        eax: c.Eax,
        ebx: c.Ebx,
        ecx: c.Ecx,
        edx: c.Edx,
        ebp: c.Ebp,
        esp: c.Esp,
        esi: c.Esi,
        edi: c.Edi,
        eip: c.Eip,
        eflags: c.EFlags as u32,
        cs: c.SegCs as u16,
        ds: c.SegDs as u16,
        es: c.SegEs as u16,
        fs: c.SegFs as u16,
        gs: c.SegGs as u16,
        ss: c.SegSs as u16,
    }
}

#[cfg(target_arch = "x86_64")]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct Registers32 {
    pub eax: u32,
    pub ebx: u32,
    pub ecx: u32,
    pub edx: u32,
    pub ebp: u32,
    pub esp: u32,
    pub esi: u32,
    pub edi: u32,
    pub eip: u32,
    pub eflags: u32,
    pub cs: u16,
    pub ds: u16,
    pub es: u16,
    pub fs: u16,
    pub gs: u16,
    pub ss: u16,
}

#[cfg(target_arch = "aarch64")]
#[derive(Copy, Clone)]
pub struct Registers32 {   // pt_regs: https://android.googlesource.com/platform/external/kernel-headers/+/froyo/original/asm-arm/ptrace.h
    pub regs: [reg_t; 18],
}

#[cfg(target_arch = "x86")]
pub type Registers32 = Registers;

pub enum RegType {
    X86(Registers32),
    X64(Registers),
    // Arm(ArmRegs),
    // Arm64(Arm64Regs),
}

pub trait UDbgRegs: AsByteArray {
    fn get_reg(&self, id: u32) -> Option<CpuReg>;
    fn set_reg(&mut self, id: u32, val: CpuReg);

    fn to_regs(&self) -> RegType;

    #[cfg(windows)]
    fn as_raw(&self) -> Option<&CONTEXT> { None }
    #[cfg(windows)]
    fn as_wow64(&self) -> Option<&WOW64_CONTEXT> { None }
}

pub fn get_regid(r: &str) -> Option<u32> {
    Some(match r {
        "rax" => X86_REG_RAX,
        "rbx" => X86_REG_RBX,
        "rcx" => X86_REG_RCX,
        "rdx" => X86_REG_RDX,
        "rbp" => X86_REG_RBP,
        "rsp" => X86_REG_RSP,
        "rsi" => X86_REG_RSI,
        "rdi" => X86_REG_RDI,
        "r8" => X86_REG_R8,
        "r9" => X86_REG_R9,
        "r10" => X86_REG_R10,
        "r11" => X86_REG_R11,
        "r12" => X86_REG_R12,
        "r13" => X86_REG_R13,
        "r14" => X86_REG_R14,
        "r15" => X86_REG_R15,
        "rip" => X86_REG_RIP,
        "eax" => X86_REG_EAX,
        "ebx" => X86_REG_EBX,
        "ecx" => X86_REG_ECX,
        "edx" => X86_REG_EDX,
        "ebp" => X86_REG_EBP,
        "esp" => X86_REG_ESP,
        "esi" => X86_REG_ESI,
        "edi" => X86_REG_EDI,
        "eip" => X86_REG_EIP,
        "_pc" => COMM_REG_PC,
        "_sp" => COMM_REG_SP,
        "eflags" => X86_REG_EFLAGS,
        _ => if r.starts_with("xmm") {
            u32::from_str_radix(&r[3..], 10).map(|i| X86_REG_XMM0 + i).ok()?
        } else if r.starts_with("mm") {
            u32::from_str_radix(&r[2..], 10).map(|i| X86_REG_MM0 + i).ok()?
        } else if r.starts_with("dr") {
            u32::from_str_radix(&r[2..], 10).map(|i| X86_REG_DR0 + i).ok()?
        } else { return None }
    })
}